package com.sds.prolog.services;


import com.google.inject.Inject;
import com.sds.prolog.dao.PrologDAO;
import com.sds.prolog.model.Laptop;
import com.sds.prolog.model.PrologSystemInfo;
import com.sds.prolog.model.Question;
import com.sds.prolog.model.Rule;
import com.sds.system.SystemConstants;
import com.sds.system.services.FileManager;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Logger;

@Path("prolog")
public class PrologService implements SystemConstants {

    private final Logger logger = Logger.getLogger(getClass().getName());
    private final PrologDAO prologDAO;
    private final FileManager fileManager;

    @Inject
    public PrologService(PrologDAO prologDAO, FileManager fileManager) {
        this.prologDAO = prologDAO;
        this.fileManager = fileManager;
        autoLoadResources();
    }

    @POST
    @Path("/parse/{fileName}")
    @Produces(MediaType.TEXT_PLAIN)
    public Response parseFile(@PathParam("fileName") final String fileName, @FormParam("user") String userName, @FormParam("pass") String password, @Context HttpServletResponse response, @Context HttpServletRequest request) {
        try {
            return securedRun(userName, password, response.getWriter(), request, new CallDelegate() {
                @Override
                public String call() throws IOException {
                    logger.info("Parsing " + fileName);
                    parseFile(fileName);
                    return "OK";
                }
            });
        } catch (IOException e) {
            logger.warning("[" + e.getClass().getName() + "]" + e.getMessage());
            return Response.serverError().build();
        }
    }

    @POST
    @Path("/content/reset")
    @Produces(MediaType.TEXT_PLAIN)
    public Response resetData(@FormParam("user") String userName, @FormParam("pass") String password, @Context HttpServletResponse response, @Context HttpServletRequest request) {
        try {
            return securedRun(userName, password, response.getWriter(), request, new CallDelegate() {
                @Override
                public String call() throws IOException {
                    logger.info("Cleaning the DB ");
                    prologDAO.getObjectManager(Question.class).deleteAll().perform();
                    prologDAO.getObjectManager(Rule.class).deleteAll().perform();
                    prologDAO.getObjectManager(Laptop.class).deleteAll().perform();
                    fileManager.getFile("/laptop.txt",true);
                    fileManager.getFile("/rule.txt",true);
                    fileManager.getFile("/question.txt",true);
                    return "All content cleared";
                }
            });
        } catch (IOException e) {
            logger.warning("[" + e.getClass().getName() + "]" + e.getMessage());
            return Response.serverError().build();
        }
    }

    private Response securedRun(
            String userName,
            String password,
            PrintWriter writer,
            HttpServletRequest request,
            CallDelegate callDelegate) {
        try {
            if (StringUtils.equals(userName, FILE_ADMIN_USERNAME) && StringUtils.equals(password, FILE_ADMIN_PASSWORD)) {
                if (callDelegate != null) {
                    writer.write(callDelegate.call());
                }
            } else {
                writer.write("Invalid username or password");
                logger.warning("Unauthorized access from " + request.getRemoteAddr());
            }
            return Response.ok().build();
        } catch (IOException e) {
            logger.warning("[" + e.getClass().getName() + "]" + e.getMessage());
            return Response.status(Response.Status.NOT_FOUND).build();
        } catch (RuntimeException e) {
            logger.warning("[" + e.getClass().getName() + "]" + e.getMessage());
            writer.println(e.getMessage());
            return Response.ok().build();
        }
    }

    private void parseFile(String fileName) throws IOException {
        prologDAO.parseAndUpdate(fileManager.getFile("/" + fileName).openForRead());
    }

    private void autoLoadResources() {
        PrologSystemInfo prologSystemInfo = prologDAO.getSystemInfo();
        //refresh every 30 mins
        if (System.currentTimeMillis() - prologSystemInfo.getLastRefresh() > REFRESH_COOL_DOWN) {
            try {
                logger.info("Auto parsing 'laptop.txt' !");
                parseFile("laptop.txt");
                logger.info("Auto parsing 'rule.txt' !");
                parseFile("rule.txt");
                logger.info("Auto parsing 'question.txt' !");
                parseFile("question.txt");
            } catch (IOException ex) {
                logger.warning("[" + ex.getClass().getName() + "]" + ex.getMessage());
            } catch (Exception ex) {
                logger.warning("[" + ex.getClass().getName() + "]" + ex.getMessage());
            }
            prologSystemInfo.setLastRefresh(System.currentTimeMillis());
            prologDAO.saveSystemInfo(prologSystemInfo);
        }
    }

    private interface CallDelegate {
        String call() throws IOException;
    }
}
